... und dazu etwas Software

Arnulf Sopp

Wie nützlich ein Umbau am Computer ist, zeigt sich natürlich erst, wenn er etwas zu tun bekommt. Das folgende Programm ist nur ein Beispiel, was man mit dem Versechzehnfacher anfangen kann. Jedes andere Maschinenprogramm, sogar BASIC-, Pascal- oder sonstige höhere Programmtexte können dort untergebracht werden (1,2), natürlich auch Datenbytes für Tabellen und dergleichen. Damit ist das leidige Himem-Thema von Tisch; nahezu jede popelige BASIC-Verschönerung (eingerückte Zeilennummern und ähnlich überflüssiges) drängelt sich dort oben und verschleißt den Platz für wirklich Wichtiges.

Dieses Programm ist ein Treiber für die HRG 1b von RB-Elektronik. Er lädt selbsttätig BASIC/CMD und arbeitet anschließend im Hintergrund mit BASIC zusammen. Sein Ladebereich geht von 3000-32E4. Dahinter sind noch ein paar Bytes als Datenpuffer reserviert. Um beim Laden des Treibers nicht den DOS-Fehler "Ladeversuch auf ROM-Speicherplatz" serviert zu bekommen, muß dort natürlich RAM vorhanden sein. Der User gibt deshalb zuvor auf den Port F0 die Nummer eines Steckplatzes auf dem Versechzehnfacher aus, wo ein statisches RAM sitzt. Unter H-DOS geht das mit OUT F0,xx (7). Ansonsten kann man zunächst BASIC starten und dann OUT 240,xx anschließend CMD"S=HRG" eingeben (sofern man dieses Programm unter dem Namen HRG/CMD auf Disk stehen hat).

A propos H-DOS: Da der Befehl CMD > (mehr darüber weiter unten) das Parallel-RAM auf der CPU-Platine benutzt, müssen Besitzer des EG 64 MBA mit diesem DOS zuvor INI.N eingeben. Damit werden zwar die interessantesten Features von H-DOS disabled, aber noch immer hat der User alle G-DOS-Möglichkeiten und noch ein bißchen mehr. Auf allen Maschinen, mit denen Banking nicht möglich ist, funktioniert dieser Befehl ganz einfach nicht, ohne aber Schaden anzurichten oder zu einem Fehler zu führen.

Der Treiber stellt eine Reihe von Kommandos an die HRG zur Verfügung. Sie alle beginnen mit CMD (1). Um dem Interpreter anzuzeigen, daß es sich nicht um das gewohnte CMD handelt, folgt unmittelbar darauf nicht eine Variable oder ein Ausdruck zwischen Gänsefüßchen, sondern ein zweites BASIC-Token:

CMD +		: HRG einschalten
CMD -		: HRG ausschalten
CMD CLS		: HRG-Speicher löschen
CMD SET		: einen HRG-Punkt setzen
CMD RESET	: einen HRG-Punkt löschen
CMD POINT	: testen, ob ein HRG-Punkt gesetzt ist
CMD <		: HRG invertieren (weiß <-> schwarz)
CMD LPRINT	: HRG-Inhalt auf Drucker ausgeben (Hardcopy)
CMD ASC		: ASCII-Bildschirm in Hex anzeigen, bis neue Taste gedrückt
CMD >		: Bildschirm gegen Pufferinhalt austauschen
CMD LINE	: noch nicht programmiert, ergibt aber keinen Fehler

Nach der üblichen BASIC-Syntax können CMD und das zweite Token direkt oder durch Blank getrennt hintereinander stehen. Diese Befehle können im Direktmodus und als Bestandteil eines Programms eingegeben werden.

Die drei erstgenannten HRG-Befehle bedürfen keiner näheren Erläuterung. CMD SET, CMD RESET und CMD POINT haben eine ganz ähnliche Syntax wie die gewohnten Befehle zur Ansteuerung der Genie-Pixelgraphik. Im Argument sind im Unterschied dazu jedoch Koordinaten im Bereich 0-383 für X und 0-191 für Y zulässig, entsprechend der feineren HRG-Matrix. Die Koordinaten können wie in Level 2 oder Disk-BASIC auch durch Variable dargestellt werden.

CMD < macht aus jedem Punkt im HRG-Speicher sein Komplement. Gesetzte Punkte werden dunkel, nicht gesetzte werden eingeschaltet. Es entsteht eine negative Darstellung. Der normale ASCII-Bildschirm bleibt hiervon unberührt.

Bei einem Bildschirmausdruck der HRG mit CMD LPRINT wird der Drucker zunächst in den Einschaltzustand versetzt (Reset aller Druckparameter). Danach wird der linke Rand auf die 9. Stelle gesetzt, um das Bild zu zentrieren. Der Zeilenabstand wird mit 6/72" so eingestellt, daß die Druckzeilen lückenlos untereinander stehen. Nach getaner Arbeit werden diese Steuercodes alle wieder gelöscht; der Drucker ist wieder im Einschaltzustand. Diese Codes gelten für den Star Gemini-10X. Für andere Printer müssen sie entsprechend geändert werden. Von den vergleichbaren Epson-Typen ist mir bekannt, daß für die Randeinstellung lediglich in ESC M 09 aus dem "M" ein "1" gemacht zu werden braucht. Die übrigen Codes sind identisch.

Der Befehl CMD ASC ist für vielerlei Verwendungen interessant. Mit ihm hat der Programmierer sozusagen immer eine ASCII-Tabelle auf dem Bildschirm. Die ASCII-Zeichen werden als zweistellige Hexzahlen dargestellt (4). So werden gleiche Zeichen mit verschiedenen Codes unterscheidbar, um nur eine Anwendung zu nennen: Die beiden Blanks mit den Codes 32 und 128 sowie die Graphikblocks 128-191 und 192-255 sind als Hexzahlen eindeutig zu identifizieren. Bei der Ausführung von CMD ASC werden die 32er Blanks übrigens nicht mit umgewandelt, sondern als Leerzeichen belassen, um den Bildschirm übersichtlich zu halten.

Dabei wird der normale ASCII-Bildschirm natürlich gelöscht, sonst würde er stören. Der Treiber rettet ihn in den HRG-Speicher, so daß -er nach dem Druck auf irgendeine Taste wieder restauriert werden kann. Ein besonderer Puffer im RAM ist dafür nicht erforderlich.

Nach diesem Schema geht auch der Befehl CMD > vor. Zunächst wird der Bildschirm in die HRG gerettet. Von ihr sind nämlich nur 6 Bits pro Byte sichtbar, die beiden höchstwertigen Bits sind unbenutzt und können den Bildschirm aufnehmen. Dabei wird der sichtbare Inhalt des HRG-Speichers nicht beeinträchtigt. Alle Graphiken bleiben also erhalten. Im weiteren Verlauf der Ausführung dieses Befehls wird nun der Inhalt der HRG, also Graphik und ASCII, in einen Puffer gerettet, und der Inhalt dieses Puffers geht dafür in die HRG.

Die beiden höchstwertigen Bits des neuen HRG-Inhalts werden in den ASCII-Bildschirm übertragen. Es ist demnach ein Austausch Bildschirm gegen Puffer. In diesem Treiber liegt der Puffer im Adreßbereich ab 0000. Das ist natürlich nur mit dem EG 64 MBA oder einem anderen Banker realisierbar.

Entsprechende Änderungen, um stattdessen das gute alte Himem dafür zu benutzen, sind kein Problem.

Der Befehl CMD LINE soll eines fernen Tages, wenn der Autor mal wieder Lust hat, an dem Treiber weiterzuarbeiten, Linien, Rechtecke usw. ziehen. Der Leser möge mir nachsehen, daß die Computerei mein Hobby ist, bei dem ich gnadenlos dem Lustprinzip folge (6).

An diesem fernen Tage werden wohl noch ein paar andere Modifikationen folgen, die es ermöglichen. den HRG-Treiber fest in ein EPROM zu brennen. Das ist mit dieser Version nicht möglich, denn das Programm vollzieht Schreibzugriffe in seinem eigenen Adreßraum. Dazu gehören z. B. die Datenpuffer an seinem Ende, aber auch variable Sprungdistanzen mitten im Programm (Selbstmodifikation). Der Vorteil dieser Variante ist freilich, daß der Treiber mit den Bedürfnissen jederzeit mitwachsen kann. Immerhin sind noch eineinviertel kB frei!

Auf die Programmlogik möchte ich an dieser Stelle nicht eingehen. Die siebeneinhalb Seiten Listing wären halbwegs erschöpfend wohl nicht mit weniger als 15 Seiten Test erklärbar. Insbesondere diejenigen Features, die kein anderer mir bekannter HRG-Treiber zur Verfügung stellt, würden einige Seiten füllen: Z. B. die Umwandlung des ASCII-Bildschirms in die Hexdarstellung und das Puffern desselben im HRG-Speicher. Der Maschinensprache-Freak mag sich dabei amüsieren, sich in dem sehr ausführlich kommentierten Listing selber zurechtzufinden.

Zu diesem Thema sind an gleicher Stelle auch bereits ein paar Beiträge erschienen, die die Arbeit deutlich erleichtern werden (5 u.a.).

Nur einige wenige Kommentare, ohne die sich sogar der Autor kaum noch im Programm zurechtfindet, sollen angefügt sein: In BASIC/CMD steht nach dem Laden (also noch vor dem Ansprung!) an 67DD der CMD-Vektor (JP 57FF). Er wird durch JP cmd (3074) ersetzt. Andere Treiber benutzen kein bereits vorhandenes Token und verlangsamen damit den ganzen Computer: es muß bei jeder Eingabe geprüft werden, ob ein vorangestelltes Doppelkreuz o. dergl. ein Syntaxfehler oder die Einleitung eines HRG-Befehls ist. An der Stelle 64F3 wird HL als Zeiger auf das BASIC-Helle geladen. Mit der Änderung des LSB von 5C auf 5E werden die beiden ersten Codes, die den Bildschirm löschen, übergangen. So bleibt die oberste Titelzeile erhalten, die beim Label hello steht.

Beim späteren Programmablauf wird der Treiber nur dann angesprungen, wenn das CMD-Token angetroffen wurde. Nun prüft er, was folgt. In Disk-BASIC ist es immer ein Anführungszeichen oder ein Variablenname. Diese Zeichen liegen im Bereich bis 7F. Der Vergleich mit 80 beim Label cmd gibt deshalb Aufschluß, ob zur Ansteuerung der HRG ein weiteres Token folgt. Falls nein, geht es in der alten CMD-Routine weiter, falls ja, kommt der Treiber jetzt so richtig in Fahrt.

Anwender, die mit EDTASM/CMD oder ASM/CMD arbeiten. müssen auf die für diese Assembler zulässige Syntax achten; Labels dürfen höchstens 6 Zeichen lang sein, Kleinbuchstaben sind nur in den Kommentaren erlaubt, DB, DW und DM müssen als DEFB, DEFW und DEFM ausgeschrieben werden.

Bei diesen Statements dürfen auch nicht mehrere Argumente in derselben Zeile stehen, schon gar nicht DEFM und DEFB gemischt. Je eine eigene Zeile muß dafür eingerichtet werden.

Dieser HRG-Treiber ist, wie gesagt, lediglich eine Demonstration dafür, was mit Helmut Bernhardts Versechzehnfacher so alles anzufangen ist. Die Platine funktioniert selbstverständlich ohne HRG, auch ohne DOS ebenso gut wie mit. Vielleicht fällt einem von euch für eins der nächsten Infos eine sinnvolle Verwendung für Level 2 ein?

Literatur:

1) "PUT TO - ein neuer BASIC-Befehl", 4/1984
2) "Bank Selection mit dem Genie I", 5/1985
3) "Neuer DOS-Befehl: OUT port#,xx,yy,...", 11/1984
4) "VIDHEX - Hexanzeige des Bildschirms mit der HRG", 9/1985
5) "Die HRG 1b programmieren", 11/1984
       (alle von A. Sopp im Club-Info des Genie/TRS80-User-Club Bremerhaven, Ausgabe jeweils angegeben).
6) R. Goscinny, M. Uderzo: "Asterix und der Kupferkessel", Dargaud S. A. 1969


		00001 	;
		00002 	;
		00003	; BASIC-Treiber für die HRG 1b von RB-Elektronik
		00004	;
		00005	; Demo-Programm zum Speicher-Versechzehnfacher
		00006	; im Adreßraum 3000-370F von Helmut Bernhardt
		00007	;
		00008	;	(C)	Arnulf Sopp
		00009	;
		00010 	;
		00011	
3000		00012		ORG	3000h		;im Sonder-ROM-Bereich
		00013	
		00014	;DOS-Eingabepuffer retten
3000	11E432	00015	finit	LD	DE,cmdbuf	;Puffer für Aufrufbefehl
3003	014800	00016		LD	BC,0048h	;ca. Lng. DOS-Eing.-puff.
3006	E5	00017		PUSH	HL		;Aufrufbefehl retten,
3007	D5	00018		PUSH	DE		;weil 4419 den Puffer-
3008	C5	00019		PUSH	BC		;Inhalt verändert
3009	EDB0	00020		LDIR			;zwischenspeichern
		00021
		00022	;Initialisierungen in BASIC/CMD
3008	212C30	00023		LD	HL,command	;BASIC-Ladekommando
300E	CD1944	00024		CALL	4419h		;BASIC/CMD laden
3011	217430	00025		LD	HL,cmd		;neuer CMD-Vektor
3014	22DD67	00026		LD	(67ddh),HL	;in BASIC/CMD laden
3017	3E5E	00027		LD	A,5eh		;LSB des BASIC-Logo
3019	32F464	00028		LD	(64f4h),A	;CLS verhindern
301C	213830	00029		LD	HL,hello	;HRG-Logo
301F	CD6744	00030		CALL	4467h		;anzeigen
3022	C1	00031		POP	BC		;Länge Eingabepuffer
3023	E1	00032		POP	HL		;Aufrufbefehl
3024	D1	00033		POP	DE		;Adresse Eingabepuffer
3025	D5	00034		PUSH	DE		;brauchen wir gleich
3026	EDB0	00035		LDIR			;Befehl restaurieren
3028	E1	00036		POP	HL		;Befehlserweit. oder CR
3029	C3BE66	00037		JP	66beh		;BASIC-Kaltstart
		00038	
		00039	;DOS-Befehl, um BASIC in den Speicher zu laden
302C	6C	00040	command	DM	'load,basic/cmd',0dh
		00041
		00042	;neue 1. Zeile des BASIC-Hello
3038	1C	00043	hello	DM	1ch,1fh,'H R G	1 b - Utility von	'
3056	54	00044		DM	'The HACKTORY Arnulf Sopp für',Oah,0dh
		00045	
		00046	;BASIC-Erweiterung für HR-Graphikbefehle
3074	FE80	00047	cmd	CP	80h		;Graphik-CMD-Befehl?
3076	DAFF57	00048		JP	C,57ffh		;norm. weiter, falls nein
		00049
		00050	;Es ist ein HRG-Befehl. Erkennen und ausführen:
3079	FED4	00051		CP	0d4h		;Bildschirm austauschen?
307B	2029	00052		JR	NZ,CLS		;falls nein
		00053
		00054	;CMD >:	Bildschirm gegen Pufferinhalt austauschen
307D	E5	00055		PUSH	HL		;Befehlszeiger
307E	CD5332	00056		CALL	vidsav		;Bildschirm retten
3081	F3	00057		DI			;bloß keine Störungen!
3082	3E08	00058		LD	A,8		;RD RAM 0000-2FFF
3084	D3DF	00059		OUT	(0dfh),A	;auf Banking-Port ausg.
3086	3C	00060		INC	A		;WR RAM 0000-2FFF
3087	D3DF	00061		OUT	(0dfh),A	;dto.
3089	65	00062		LD	H,L		;HL <- 0000, Pufferadr.
308A	55	00063		LD	D,L		;DE <- 00xx, HRG-Adresse
3088	50	00064		LD	E,L		;DE <- 0000
308C	0E30	00065		LD	C,30h		;Konst. HRG-MSB
308E	CD4B32	00066	swaplop CALL	HRGadr		;HRG-Stelle adressieren
3091	DB04	00067		IN	A,(4)		;HRG-Byte laden
3093	46	00068		LD	B,(HL)		;Pufferbyte holen
3094	77	00069		LD	(HL),A		;HRG-Byte puffern
3095	78	00070		LD	A.B		;Pufferbyte
3096	0305	00071		OUT	(5),A		;auf HRG ausgeben
3098	23	00072		INC	HL		;Pufferzeiger erhöhen
3099	7A	00073		LD	A,D		;überprüfen, ob
309A	89	00074		CP	C		;HkG-Bereich überschr.?
3098	38F1	00075		JR	C,swaplop	;falls nein
309D	DBDF	00076		IN	A,(0dfh)	;Banks rücksetzen
309F	FBI	00077		EI			;INTs wieder zulassen
30A0	CD5532	00078		CALL	savrest		;Bildsch.	restaurieren
30A3	E1	00079		POP	HL		;Befehlszeiger
30A4	1831	00080		JR	exit1		;fertig
		00081		
		00082	;CMD CLS: HRG-Speicher löschen	
30A6	FE84	00083 	CLS	CP	84h		;CLS?
30A8	2004	00084		JR	NZ,INV		;falls nein
30AA	1E00	00085 	clear	LD	E,0		;Flag für HRG-CLS
30AC	1806	00086		JR	clsinv		;dort weiter
		00087		
		00088 	;CMD <: HRG invertieren (positiv -> negativ)
30AE	FED6	00089 	INV	CP	Od6h		;invertieren?
3080	2027	00090		JR	NZ,LINE		;falls nein
3082	1EFF	00091		LD	E,0ffh		;Flag für Inversion
3084	010330	00092 	clsinv	LD	BC,3003h	;8 = MSB 12kB, C = Port 3
3087	C5	00093 	msloop	PUSH	BC		;retten
30B8	05	00094		DEC			;B um 1 zu hoch
30B9	ED41	00095		OUT	(C),B		;MSB HRG-Adresse
3088	0600	00096		LD	B,0		;B <- 0 für HRG-LSB
30BD	0D	00097		DEC	C		;Port 2 für LSB
308E	ED41	00098 	lsloop	OUT	(C),B		;LSB HRG-Adresse
3000	DB04	00099		IN	A,(4)		;HRG-Byte holen
30C2	F5	00100		PUSH	AF		;retten
30C3	E6C0	00101		AND	0c0h		;obere Bits isolieren
3005	57	00102		LD	D,A		;und retten
3006	F1	00103		POP	AF		;HRG-Byte
3007	2F	00104		CPL			;invertieren
3008	E63F	00105		AND	3fh		;obere Bits ausmaskieren
30CA	CB7B	00106		BIT	7,E		;CLS oder INV?
30CC	2001	00107		JR	NZ,outa		;falls INV
30CE	AF	00108		XOR	A		;sonst löschen
30CF	82	00109 	outa	OR	D		;obere Bits hinzufügen
3000	0305	00110		OUT	(5),A		;Blank od. Kompl. ausgeb.
3002	10EA	00111		DJNZ	lsloop		;LSB: 00, FF, FE ... 01
3004	C1	00112		POF	BC		;MSB und Port für MSB
3005	10E0	00113		DJNZ	msloop		;MSB-1:	2F ... 00
		00114
		00115 	;Rückkehr für mehrere Unterprogramme
3007	23	00116 	exit1	INC	HL		;Befehlszeiger nachst.
3008	C9	00117		RET			;erledigt
		00118
		00119 	;CMD LINE:	(bisher nicht programmiert)
3009	FE9C	00120 	LINE	CP	9ch		;LINE?
3008	28FA	00121		JR	Z,exit1		;vorl. nicht implement.
		00122
		00123 	;CMD 4:	HRG-Speicher in den Bildschirm einblenden
3000	FECD	00124		CP	Ocdh		;HRG einschalten?
30DF	2004	00125		JR	NZ,HRGoff	;falls nein
30E1	0301	00126		OUT	(1),A		;einschalten
30E3	18F2	00127		JR	exit1		;fertig
		00128
		00129 	;CMD -	HRG-Speicher aus dem Bildschirm ausblenden
30E5	FECE	00130 	HRGoff	CP	Oceh		;HRG ausschalten?
30E7	2004	00131		JR	NZ,LPRINT	;falls nein
30E9	0300	00132		OUT	(0),A		;ausschalten
30EB	18EA	00133		JR	exit1		;fertig	
30ED	FEAF	00134
30EF	2066	00135 ;CMD LPRINT: Hardcopy des HRG-Speichers	
		00136 LPRINT	CP	0afh		;LPRINT (Hardcopy)?
		00137		JR	NZ,ASC		;falls nein
		00138	
		00139 ;LPRINT;	Drucker initial.: Reset, 6/72" Zeilenabstand
30F1	E5	00140		PUSH	HL		;Befehlszeiger retten
30F2	210632	00141		LD	HL,prestor+1	;Druckerinitialisierung
30F5	0609	00142		LD	B,9		;mit 9 Codes
30F7	CDFC31	00143		CALL	lprint		;Ausgabe auf Drucker
		00144	
		00145 ;HRG-Zeiger laden, 16 (Doppel-)Zeilen vorbereiten
30FA	50	00146		LD	D,B		;DE <- 00xx
30FB	58	00147		LD	E,B		;DE <- 0000, Start HRG
30FC	010610	00148		LD	BC,1006h	;16 Zeilen, Konst. 6
		00149	
		00150 ;1 Doppelzeile zu je 6 Dotzeilen drucken
30FF	C5	00151 scrnlop	PUSH	BC		;Zähler retten
3100	D5	00152		PUSH	DE		;dto. HRG-Zeiger
3101	0602	00153		LD	B,2		;2 Halbzeilen/Zeile
3103	C5	00154 linelop PUSH	BC		;wird verändert
3104	D5	00155		PUSH	DE		;dto. HRG-Zeiger
3105	21DF32	00156		LD	HL,lninit	;Druckerinit. für 1 Zeile
310B	0605	00157		LD	B,5		;mit 5 Codes
310A	CDFC31	00158		CALL	lprint		;Ausgabe
3100	21E432	00159		LD	HL,buffer	;Puffer für Druckercodes
3110	0640	00160		LD	B,40h		;64 Bytes/Zeile
		00161
		00162 ;1 Halbzeile drucken	
3112	C5	00163 hlinlop	PUSH	BC		;Zähler retten
3113	D5	00164		PUSH	DE		;dto. HRG-Zeiger
3114	78	00165		LD	A,E		;LSB des HRG-Zeigers
3115	D302	00166		OUT	(2),A		;auf HRG ausgeben
3117	41	00167		LD	B,C		;6 Bytes senkrecht
		00168
		00169 :1 Byte drucken	
3118	C5	00170 bytelop	PUSH	BC		;wird verändert
3119	7A	00171		LD	A,D		;MSB des HRG-Zeigers
311A	0303	00172		OUT	(3);A		;auf HRG ausgeben
311C	DB04	00173		IN	A,(4)		;Dotzeile aus HRG
311E	41	00174		LD	B,C		;6 Dots/Stelle
311F	E5	00175		PUSH	HL		;retten
		00176
		00177 ;6mal 1 Bit errechnen	
3120	0F	00178 bitlop	RRCA			;Cy <- HRG-Bit
3121	CB16	00179		RL	(HL)		;nächstes Pufferbit <- Cy
3123	CBB6	00180		RES	6,(HL)		;nur untere Bits
3125	23	00181		INC	HL		;nächstes Pufferbyte
3126	10F8	00182		DJNZ	bitlop		;bis 6 Dots gepuffert
		00183	
		00184 ;6 Bits fertig - 6 Bytes vervollständigen	
3128	14	00185		INC	D		;MSB auf nächste Dotzeile
3129	14	00186		INC	D		;= um 1 kB erhöhen)
312A	14	00187		INC	D	
3120	14	00188		INC	D	
312C	E1	00189		POP	HL		;Pufferzeiger
312D	C1	00190		POP	BC		;Zähler
312E	10E8	00191		DJNZ	bytelop		;bis 1 Stelle im Puffer
		00192
		00193 ;6 Bytes ausdrucken und weiter mit Halbzeile
3130	E5	00194		PUSH	HL		;wird verändert
3131	41	00195		LD	B.0		;6 Dotspalten
3132	CDFC31	00196		CALL	lprint		;ausgeben
3135	E1	00197		POP	HL		;Pufferzeiger
3136	D1	00198		POP	DE		;alter HRG-Zeiger
3137	13	00199		INC	DE		;nächstes HRG-Byte
3138	C1	00200		POP	BC		;Halbzeilenzähler
3139	1007	00201		DJNZ	hlinlop		;bis 1 Halbzeile gedruckt
		00202	
		00203 ;Ganzzeile vervollständigen
3138	D1	00204		POP	DE		;HRG-Zeiger
31330	3E18	00205		LD	A.18h		;6 Dotzeilen (6 kB)
313E	B2	00206		ADD	A,D		;zum MSB addieren
313F	57	00207		LD	D,A		;neu laden
3140	C1	00208		POP	BC		;Zeilenzähler
3141	1000	00209		DJNZ	linelop		;bis 12 Dotzeilen gedr.
		00210	
		00211 ;weiter mit der nächsten Zeile
3143	D1	00212		POP	DE		;HRG-Zeiger
3144	214000	00213		LD	HL,0040h	;Summand 64
3147	19	00214		ADD	HL,DE		;LSB um eine Zeile erhöh.
3148	EB	00215		EX	DE,HL		;Zeiger <- neuer Wert
3149	C1	00216		POP	BC		;Zeilenzähler
314A	1083	00217		DJNZ	scrnlop		;bis Bildschirm gedruckt
		00218	
		00219	;fertig - Drucker wieder in Normalstatus versetzen	
314C	210532	00220		LD	HL,prestor	;Dr. reinitialisieren
314F	0604	00221		LD	B,4		;mit 4 Codes
3151	CDFC31	00222		CALL	lprint		;Ausgabe
3154	E1	00223		POP	HL		;Befehlszeiger
3155	23	00224 exit2	INC	HL		;Befehlszeiger aktualis.
3156	C9	00225		RET			;und raus
		00226
		00227 ;CMD ASC: Bildschirmanzeige in Hex umwandeln
3157	FEF6	00228 ASC	CP	0f6h		;ASC?
3159	2026	00229		JR	NZ,PSR		;falls nein
3158	ES	00230		PUSH	HL		;Befehlszeiger retten
315C	CDAA30	00231		CALL	clear		;HRG-Speicher löschen
		00232	
		00233 ;Bildschirm retten
315E	D301	00234		OUT	(1),A		;HRG einschalten
3161	CD5332	00235		CALL	vidsav		;Bildschirm retten
		00236	
		00237 ;Bildschirm von ASCII- in Hexanzeige ändern	
3164	263C	00238		LD	H,3ch		;Bildschirmanfang	
3166	E5	00239 hexdisp	PUSH	HL		;dto.
3167	4E	00240		LD	C,(HL)		;Bildschirmzeichen
3168	3E20	00241		LD	A,' '		;Blank
316A	B9	00242		CP	C		;Blank?	(nicht verändern)
316B	77	00243		LD	(HL),A		;diese Stelle löschen
316C	C40832	00244		CALL	NZ,byte		;kein Bl., 1 Byte umwand.
		00245	
		00246 ;Zeichen umgewandelt oder Blank überspr.; nächst.	Zeichen
316E	E1	00247		POP	HL		;Bildschirmzeiger
3170	23	00248		INC	HL		;nächste Stelle
3171	C874	00249		BIT	6,H		;Bildsch. überschritten?
3173	28F1	00250		JR	Z,hexdisp	;nein, nächstes Byte
3175	CD4900	00251 
		00252 ;Nach Anzeige auf Tastendruck warten, dann Bildschirm restaur.
		00253		CALL	0049h		;auf Taste warten	
3178	4D	00254		LD	C,L		;C <- 00, Bildsch. rest.
3179	CD5532	00255		CALL	savrest		;UP abarbeiten
317C	0300	00256		OUT	(0),A		;HRG ausschalten
317E	E1	00257		POP	HL		;Befehlszeiger
317F	1804	00258		JR	exit2		;und raus
		00259	
		00260 ;CMD POINT, CMD SET oder CMD RESET
3181	CDA131	00261 PSR	CALL	argum		;Ausdruck auswerten	
3184	FE82	00262		CP	82h		;RESET?
3186	2908	00263		JR	Z,reset	
3188	FE83	00264		CP	83h		;SET?
318A	280A	00265		JR	Z,set
318C	FEC6	00266		CP	0c6h		;POINT?
318E	2800	00267		JR	Z,point
3190	1808	00268		JR	PSRexit		;falls Fehler
		00269		
		00270	;CMD RESET	
3192	78	00271	reset	LD	A,B		;HRG-Byte laden
3193	A9	00272		XOR	C		;Bit rücksetzen
3194	1802	00273		JR	out		;Ausgabe und zurück
		00274
		00275	;CMD SET	
3196	78	00276	set	LD	A,8
3197	81	00277		OR	C		;Bit setzen
3198	D305	00278	out	OUT	(5),A		;auf HRG ausgeben
		00279		
		00280	;gemeinsamer Rücksprung für CMD RESET und SET
319A	C38C01	00281	PSRexit JP	018ch		;-> BASIC
		00282		
		00283	;CMD POINT - Flag für Dot ja oder nein in (CMDBUF)
319D	78	00284	point	LD	A,B
319E	C39201	00285		JP	0192h		;weiter wie Level 2
		00286		
		00287	;CMD POINT, SET	oder RESET - Argument ausrechnen
3141	F5	00288	argum	PUSH	AF		;Token retten
3142	23	00289		INC	HL		;Befehlszeiger nachstell.
3143	CF	00290		RST	08h		;auf '1' prüfen
3144	28	00291		DB	'1'		;sonst Syntaxfehler
3145	CD461E	00292		CALL	1e46h		;DE <- Abszisse
3148	E5	00293		PUSH	HL		;Befehlszeiger retten
3149	217F01	00294		LD	HL,017fh	;Maximalwert für X
31AC	DF	00295		RST	18h		;Vergleich mit Eingabe
314D	E1	00296	fcterr	POP	HL		;Befehlszeiger restaur.
314E	04441E	00297		JP	C,1e4ah		;Funktionsf., falls mehr
3181	D5	00298		PUSH	DE		;Abszisse retten
3182	CF	00299		RST	08h		;auf ',' prüfen
3183	2C	00300		DB	','		;sonst Syntaxfehler
3184	CD461E	00301		CALL	1e46h		;DE <- Ordinate
3187	E5	00302		PUSH	HL		;Befehlszeiger retten
3188	218F00	00303		LD	HL,00bfh	;Maximalwert für Y
3188	DF	00304		RST	18h		;Vergleich mit Eingabe
31BC	E1	00305		POP	HL		;Befehlszeiger restaur.
3I80	38EE	00306		JR	C,fcterr	;Fehler, falls höher
318e	22E432	00307		LD	(cmdbuf),HL	;Befehlszeiger retten
31C2	EB	00308		EX	DE,HL		;zur Vereinf. d. Folgend.
31C3	E3	00309		EX	(SP),HL		;X- <-> Y-Koordinate
3104	3E06	00310		LD	A,06h		;wegen 6 Dots/Byte
3106	CD7944	00311		CALL	4479h		;HL/A=HL Rest A
31C9	D1	00312		POP	DE		;Ordinate holen
31CA	F5	00313		PUSH	AF		;Bit-Nr. retten
3108	E5	00314		PUSH	HL		;dto. X-Koordinate
31CC	EB	00315		EX	DE,HL		;HL <- Y-Koordinate
31CD	3E0C	00316		LD	A,0ch		;wegen	12 Dotzeil./Stelle
31CF	CD7944	00317		CALL	4479h		;HL/A=HL Rest A
3102	F5	00318		PUSH	AF		;Rest retten
3103	3E40	00319		LD	A,40h		;64 Stellen/Zeile
3105	CD7644	00320		CALL	4476h		;A*HL=AHL
3108	44	00321		LD	B,H		;HL nach BC retten
31D9	4D	00322		LD	C,L
31D4	F1	00323		POP	AF		;obigen Rest holen
3108	210004	00324		LD	HL,0400h	;Faktor	1kB
310E	CD7644	00325		CALL	4476h		;A*HL=AHL
31E1	09	00326		ADD	HL,BC		;Zwischensumme
31E2	C1	00327		POP	BC		;X-Koordinate
31E3	09	00328		ADD	HL,BC		;Endsumme = HRG-Adresse
31E4	7D	00329		LD	A,L		;LSB
31E5	0302	00330		OUT	(2),A		;auf HRG ausgeben
31E7	7C	00331		LD	A,H		;MSB
31E8	D303	00332		OUT	(03h),A		;dto.
31EA	C1	00333		POP	BC		;B <- Bit-Nr.
310B	04	00334		INC	B		;B <- mindestens 1
31EC	3E80	00335		LD	A,80h		;Anfangswert für A
31EE	07	00336	doublop	RLCA			;fortgesetzt A*2
31EF	10FD	00337		DJNZ	doublop		;bis richtiges Bit in A
31F1	E63F	00338		AND	3fh		;nur die ersten 6 Bits
31F3	4F	00339		LD	C,A		;Akku retten
31F4	DB04	00340		IN	A,(4)		;Inh.	HRG-Speicherstelle
31F6	47	00341		LD	B,A		;HRG-Byte retten
31F7	F1	00342		POP	AF		;Token restaurieren
31F8	24E432	00343		LD	HL,(cmdbuf)	;Befehlszeiger restaur.
31FB	C9	00344		RET			;erledigt
		00345		
		00346 ;Zeichenfolge ab (HL) auf Drucker ausgeben
31FC	CDD105	00347 lprint	CALL	05d1h		;Drucker bereit?
31FF	20FB	00348		JR	NZ,lprint	;falls nein
3201	7E	00349		LD	A,(HL)		;zu druckendes Zeichen
3202	D3FD	00350		OUT	(0fdh),A	;auf Drucker ausgeben
3204	23	00351		INC	HL		;nächste Stelle
3205	10F5	00352		DJNZ	lprint		;nächstes Zeichen
3207	C9	00353		RET			;zurück
		00354		
		00355 ;UP Hexanzeige: 1 Byte ändern		
320E	7C	00356	byte	LD	A,H		;MSB der Videoadresse
3209	E603	00357		AND	03		;Adr. Vid. -> Adr. HRG
320B	57	00358		LD	D,A		;neues MSB
320C	SD	00359		LD	E,L		;HRG-MSB wie Video-MSB
320D	79	00360		LD	A,C		;Videozeichen
320E	E6F0	00361		AND	0f0h		;oberes Nibble
3210	0F	00362		RRCA			;ins untere schieben
3211	0F	00363		RRCA	
3212	0F	00364		RRCA	
3213	0F	00365		RRCA	
3214	21B032	00366		LD	HL,chrtab-5	;vor Tab. f. Hexzeich,
3217	E5	00367		PUSH	HL		;brauchen wir noch
3218	CD1F32	00368		CALL	nibble		;oberes Nibble anzeigen
321B	79	00369		LD	A,C		;alter Code
321C	E60F	00370		AND	0fh		;unteres Nibble
321E	E1	00371		POP	HL		;Tabellenzeiger
		00372
		00373 ;einzelnes Halbbyte in die HRG laden
321F	47	00374	nibble	LD	B,A		;als Zähler i. d. Tabelle
3220	3A3932	00375		LD	A,(displc)	;Sprungdistanz
3223	EE02	00376		XOR	output-displc-1	;umschalten
3225	323932	00377		LD	(displc),A	;neu laden
3228	04	00378		INC	B		;wegen DE = Tabelle -5
3229	23	00379 seekchr	INC	HL		;Zeiger nachstellen
322A	23	00380		INC	HL		;über 5 Stellen, weil
322B	23	00381		INC	HL		;5 Codes pro Zeichen
322C	23	00382		INC	HL	
322D	23	00383		INC	HL	
322E	10F9	00384		DJNZ	seekchr		;bis Code gefunden
3230	0605	00385		LD	B,5		;5 Dotzeilen pro Zeichen
3232	C5	00386 nibloop	PUSH	BC		;Zähler retten
3233	CD4B32	00387		CALL	HRGadr		;HRG-Stelle adressieren
3236	18	00388		DEC	DE		;HRG-Zeiger korrigieren
3237	7E	00389		LD	A,(HL)		;Dotzeile laden
3238	1B00	00390		JR	$+2		;variable Sprungdistanz
3239		00391 displc	EQU	$-1		;hier Distanzbyte
3236	07	00392		RLCA			;lower Nibble verschieben
3238	07	00393		RLCA			;um 2 Dots
323C	4F	00394 output	LD	C,A		;Dotzeile retten
323D	DB04	00395		IN	A,(4)		;HRG-Byte mit Videocode
323F	B1	00396		OR	C		;mit Dotzeile verknüpfen
3240	D305	00397		OUT	(5),A		;Dotzeile in HFG laden
3242	14	00398		INC	D		;im MSB um 1 kB erhöhen
3243	14	00399		INC	D		;für nächste Dotzeile
3244	14	00400		INC	D
3245	14	00401		INC	D
3246	23	00402		INC	HL		;nächster Code für Ziffer
3248	10E8	00404		DJNZ	nibloop		;bis Nibble angezeigt
324A	C9	00405		RET			;zurück
3247	C1	00403		POP	BC		;Zähler restaurieren
3248 10E8	00404		DJNZ	nibloop		;bis Nibble angezeigt
324A C9		00405		RET			;zurück
		00406
		00407	;UP, um die HRG-Adresse auszugeben
324B	7B	00408	HRGadr	LD	A,E		;LSB der HRG-Adresse
324C	D302	00409		OUT	(2),A		;auf Port ausgeben
324E	7A	00410		LD	A,D		;MSB
324F	D303	00411		OUT	(3),A		;dto.
3251	13	00412		INC	DE		;nächste HRG-Stelle
3252	C9	00413		RET	
		00414
		00415	;UP, um Bildschirm zu retten oder zu restaurieren
3253	0EC0	00416	vidsav	LD	C,0c0h		;Konstante
3255	210030	00417	savrest	LD	HL,3c00h	;Bildschirmadresse
3258	55	00418		LD	D,L		;DE <- 00xx, HRG-Adresse
3259	50	00419		LD	E,L		;DE <- 0000
325A	0604	00420	vidsav1	LD	B,4		;4*2 Bits/Byte
325C	CD4B32	00421	vidsav2	CALL	HRGadr		;HRG-Stelle adressieren
325F	CB79	00422		BIT	7,C		;Bildschirm retten?
3261	2812	00423		JR	Z,restor	;falls nein
3263	7E	00424		LD	A,(HL)		;Bildschirmzeichen
3264	A1	00425		AND	C		;nur oberste 2 Bits
3265	C5	00426		PUSH	BC		;C retten
3266	4F	00427		LD	C,A		;Akku retten
3267	DB04	00428		IN	A,(4)		;HRG-Byte holen
3269	E63F	00429		AND	3fh		;oberste Bits ausmaskier.
326B	B1	00430		OR	C		;Videobits zufügen
326C	C1	00431		POP	BC		;C restaurieren
326D	D305	00432		OUT	(5),A		;auf HRG ausgeben
326F	CB06	00433		RLC	(HL)		;Zeichen 2 Bits aufrücken
3271	CB06	00434		RLC	(HL)
3273	1808	00435		JR	gosave		;dort weiter
3275	OB04	00436	restor	IN	A,(4)		;HFG-Byte holen
3277	07	00437		RLCA			;2 oberste Bits
3278	CB16	00438		RL	(HL)		;in den Bildsch. laden
327A	07	00439		RLCA	
327B	CB16	00440		RL	(HL)
327D	1000	00441	gosave	DJNZ	vidsav2		;bis 1 Byte fertig
327F	23	00442		INC	HL		;nächste Videostelle
3280	CB74	00443		BIT	6,H		;Bildsch. überschritten?
3282	C0	00444		RET	NZ		;falls ja
3283	1805	00445		JR	vidsav1		;weiter, falls nein
		00446
		00447	;Codetabelle für HRG-Zeichensatz
3285	02	0044B	chrtab	DB	2,5,5,5,2	;0
328A	04	00449		DB	4,6,5,4,4	;1
328F	03	00450		DB	3,4,2,1,7	;2
3294	07	00451		DB	7,4,2,4,7	;3
3299	04	00452		DB	4,5,7,4,4	;4
329E	07	00453		DB	7,1,3,4,3	:5
3243	06	00454		DB	6,1,7,5,2	;6
3248	07	00455		DB	7,4,2,1,1	;7
32AD	02	00456		DB	2,5,2,5,2	:8
32B2	02	00457		DB	2,5,7,2,1	;9
32B7	02	00458		OB	2,5,7,5,5	;A
32BC	03	00459		DB	3,5,3,5,3	;B
3201	06	00460		DB	6,1,1,1,6	;C
32C6	03	00461		DB	3,5,5,5,3	;D
32CB	07	00462		OB	7,1,3,1,7	;E
32D0	07	00463		DB	7,1,3,1,1	;F
		00464			
		00465	;versch. Druckercodes, Puffer für Dotspalten usw.	
32D5	0D	00466	prestor	DB	0dh,0dh,1bh,'§'		;Drucker reinitialisieren
32D9	1B	00467		DB	1bh,'M',09h		;li. Rand auf 9. Stelle
32DC	18	00468		DB	1bh,'A',06h		;Zeilenabstand 6/72"
32DF	0D	00469	lninit	DB	0dh,1bh,'K',80h,01h	;Dotgr. einf. D.
32E4	0000	00470	buffer	DW	0000h,0000h,0000h	;Puffer f. HRG
32EA		00471	cmdbuf	EQU	$			;Puffer für Befehlszeiger
		00472			
3000		00473			END	finit

00000 Fehler

ASC	3157	CLS	30A6	HRGadr	3248	HRGoff	30E5	INV	30AE
LINE	30D9	LPRINT	30ED	PSR	3181	PSRexit	319A	argum	31A1
bitlop	3120	buffer	32E4	byte	3208	bytelop	3118	chrtab	3285
clear	30AA	clsinv	3084	cmd	3074	cmdbuf	32EA	command	302C
displc	3239	doublop	31EE	exit1	30D7	exit2	3155	fcterr	31AD
gosave	327D	hello	3038	hexdisp	3166	hlinlop	3112	finit	3000
linelop	3103	lninit	32DF	lprint	31FC	lsloop	308E	msloop	3087
nibble	321F	nibloop	3232	out	3198	outa	30CF	output	323C
point	319D	prestor	32D5	reset	3192	restor	3275	savrest	3255
scrnlop	30FF	seekchr	3229	set	3196	swaplop	308E	vidsav	3253
vidsavl	325A	vidsav2	325C